package com.zhuanzhuan.hero.user.service.impl;

import com.bj58.zhuanzhuan.zzentry.common.service.entity.ServiceHeaderEntity;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.zhuanzhuan.hero.biz.common.entity.risk.control.request.UnreliableCertificateRiskControlRequest;
import com.zhuanzhuan.hero.biz.common.entity.risk.control.response.RiskControlResult;
import com.zhuanzhuan.hero.biz.common.enums.RiskControlResultType;
import com.zhuanzhuan.hero.user.consts.Consts;
import com.zhuanzhuan.hero.user.consts.NumConsts;
import com.zhuanzhuan.hero.user.dto.reliable.QueryReliableListDTO;
import com.zhuanzhuan.hero.user.entity.HeroUserReliableRecord;
import com.zhuanzhuan.hero.user.enums.ExceptionMsgEnum;
import com.zhuanzhuan.hero.user.enums.ReliableAuthTypeEnum;
import com.zhuanzhuan.hero.user.enums.ReliableOperateTypeEnum;
import com.zhuanzhuan.hero.user.exception.BusinessException;
import com.zhuanzhuan.hero.user.pojo.bo.CreateReliableRecordBO;
import com.zhuanzhuan.hero.user.service.*;
import com.zhuanzhuan.hero.user.util.StringUtil;
import com.zhuanzhuan.hero.user.vo.PageResultWrapper;
import com.zhuanzhuan.hero.user.vo.UserItemBriefVO;
import com.zhuanzhuan.hero.user.vo.UserListItemVO;
import com.zhuanzhuan.hero.user.vo.reliable.CertifyReliableDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @ClassName ReliableServiceImpl
 * @Description
 * @Author hanjunjun
 * @Date 2024/7/5 14:37
 */
@Service
@Slf4j
public class ReliableServiceImpl implements IReliableService {

    @Resource
    private HeroUserReliableRecordService reliableRecordService;

    @Resource
    private IUserService userService;

    @Resource
    private ICounterService counterService;

    @Resource
    private IRiskControlService riskControlService;

    @Resource
    private IApolloService apolloService;

    @Resource
    private IPushService pushService;

    @Override
    public PageResultWrapper<UserListItemVO> pageReliables(Long fromUid, Long toUid, QueryReliableListDTO queryReliableListDTO) {
        PageInfo<HeroUserReliableRecord> pageInfo =
            PageHelper.startPage(queryReliableListDTO.getPageNum(), queryReliableListDTO.getPageSize())
                .doSelectPageInfo(() -> reliableRecordService.queryByParam(null, toUid, queryReliableListDTO.getReliableType(),
                    ReliableOperateTypeEnum.AUTH.getCode()));

        List<HeroUserReliableRecord> recordList = pageInfo.getList();
        if (CollectionUtils.isEmpty(recordList)) {
            return PageResultWrapper.empty(queryReliableListDTO);
        }

        //认证人uid
        List<Long> authUids =
            recordList.stream().map(HeroUserReliableRecord::getFromUid)
                .distinct().collect(Collectors.toList());

        List<UserItemBriefVO> userItems = userService.buildUserItem(fromUid, authUids, true, true);
        Map<Long, UserItemBriefVO> uidUserMap =
            userItems.stream().collect(Collectors.toMap(UserItemBriefVO::getUid, Function.identity()));

        List<UserListItemVO> voList =
            recordList.stream().map(authRecord -> this.convertUserListItemVO(authRecord, uidUserMap))
                .collect(Collectors.toList());

        return PageResultWrapper.wrapper(pageInfo.getTotal(), voList, pageInfo.isHasNextPage(), queryReliableListDTO);
    }

    /**
     * 是否有资格靠谱认证
     *
     * @param fromUid
     * @param toUid
     * @return boolean
     * @author  hanjunjun
     * @date 2024/7/5
     **/
    @Override
    public boolean hasCertifyQualify(Long fromUid, Long toUid) {
        if (apolloService.queryLogicSwitchConfig().getReliableCertifyQualify()) {
            //查询两个人之间的交易单数  历史交易单数>3
            return counterService.queryDealSuccessRecycleOrderNum(fromUid, toUid) > NumConsts.THREE;
        }
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void certifyReliable(Long fromUid, CertifyReliableDTO certifyReliableDTO, ServiceHeaderEntity header) {
        Long toUid = certifyReliableDTO.getToUid();

        if (Objects.equals(fromUid, toUid)) {
            log.info("不可自己给自己认证");
            throw new BusinessException(ExceptionMsgEnum.BUSINESS_ERROR);
        }
        //校验门槛
        if (!this.hasCertifyQualify(fromUid, toUid)) {
            throw new BusinessException(apolloService.queryTips().getReliableAuthNoQualified());
        }

        Integer reliableType = certifyReliableDTO.getReliableType();

        //幂等  靠谱/不靠谱记录不能同时存在，业务流程上必须取消一个才能认证另一个
        List<HeroUserReliableRecord> records =
            reliableRecordService.queryByParam(fromUid, toUid, null, ReliableOperateTypeEnum.AUTH.getCode());
        if (CollectionUtils.isNotEmpty(records)) {
            log.info("已经认证过了或者取消认证后再操作");
            throw new BusinessException(ExceptionMsgEnum.DUPLICATE_REQUEST);
        }

        //保存
        CreateReliableRecordBO saveBo = new CreateReliableRecordBO();
        saveBo.setFromUid(fromUid)
            .setToUid(toUid).setReliableType(reliableType)
            .setUnreliableReason(certifyReliableDTO.getUnReliableReason())
            .setUnreliablePics(certifyReliableDTO.getUnReliablePics())
            .setOperateType(ReliableOperateTypeEnum.AUTH.getCode());
        HeroUserReliableRecord insertEntity = reliableRecordService.insert(saveBo);

        //计数上报  靠谱数++、不靠谱数++、靠谱未读总数
        if (ReliableAuthTypeEnum.RELIABLE.getCode().equals(reliableType)) {
            //靠谱数
            counterService.userReliableNumIncre(toUid);
            //靠谱未读总数
            counterService.reliableUnreadNumIncre(toUid);
            //靠谱认证发push
            pushService.reliableSendPush(fromUid, toUid);
        } else {
            this.riskControlUnReliable(fromUid, insertEntity.getId(), certifyReliableDTO.getUnReliableReason(),
                certifyReliableDTO.getUnReliablePics(), header);
            //不靠谱数
            counterService.userUnReliableNumIncre(toUid);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void cancelReliable(Long fromUid, CertifyReliableDTO certifyReliableDTO) {
        Long toUid = certifyReliableDTO.getToUid();
        if (Objects.equals(fromUid, toUid)) {
            log.info("不可自己给自己认证");
            throw new BusinessException(ExceptionMsgEnum.BUSINESS_ERROR);
        }

        Integer reliableType = certifyReliableDTO.getReliableType();

        //幂等  是否存在认证记录
        List<HeroUserReliableRecord> records =
            reliableRecordService.queryByParam(fromUid, toUid, reliableType, ReliableOperateTypeEnum.AUTH.getCode());
        if (CollectionUtils.isEmpty(records)) {
            log.info("不存在成功认证记录，不能操作");
            throw new BusinessException(ExceptionMsgEnum.DUPLICATE_REQUEST);
        }

        //保存
        CreateReliableRecordBO saveBo = new CreateReliableRecordBO();
        saveBo.setFromUid(fromUid)
            .setToUid(toUid).setReliableType(reliableType)
            .setUnreliableReason(certifyReliableDTO.getUnReliableReason())
            .setUnreliablePics(certifyReliableDTO.getUnReliablePics())
            .setOperateType(ReliableOperateTypeEnum.CANCEL_AUTH.getCode());
        reliableRecordService.insert(saveBo);

        //删除认证靠谱记录
        reliableRecordService.delById(records.get(NumConsts.ZERO).getId());

        //计数  靠谱数--/不靠谱数--
        if (ReliableAuthTypeEnum.RELIABLE.getCode().equals(reliableType)) {
            counterService.userReliableNumDecre(toUid);
        } else {
            counterService.userUnReliableNumDecre(toUid);
        }
    }

    @Override
    public List<UserItemBriefVO> queryReliableUsers(Long uid) {
        List<HeroUserReliableRecord> records =
            reliableRecordService.queryByParam(null, uid, ReliableAuthTypeEnum.RELIABLE.getCode(),
                ReliableOperateTypeEnum.AUTH.getCode());
        if (CollectionUtils.isEmpty(records)) {
            return new ArrayList<>();
        }

        List<Long> otherUids =
            records.stream().map(HeroUserReliableRecord::getFromUid).distinct().collect(Collectors.toList());
        return userService.buildUserItem(uid, otherUids, false, false);
    }

    private UserListItemVO convertUserListItemVO(HeroUserReliableRecord authRecord, Map<Long, UserItemBriefVO> uidUserMap) {
        UserListItemVO vo = new UserListItemVO();
        vo.setId(authRecord.getId())
            .setReason(authRecord.getUnreliableReason())
            .setPics(StringUtil.str2List(authRecord.getUnreliablePics()))
            .setUserInfo(uidUserMap.get(authRecord.getFromUid()));
        vo.setCreateTime(authRecord.getCreateTime());
        return vo;
    }

    private void riskControlUnReliable(Long uid, Long authRecordId, String unReliableReason,
        List<String> unReliablePics, ServiceHeaderEntity header) {
        UnreliableCertificateRiskControlRequest riskControlRequest = new UnreliableCertificateRiskControlRequest();
        riskControlRequest.setReason(unReliableReason);
        riskControlRequest.setPictures(unReliablePics);
        RiskControlResult riskControlResult =
            riskControlService.unReliableRiskControl(uid, authRecordId, header, riskControlRequest);
        if (!(RiskControlResultType.PASS.getCode() == riskControlResult.getResult())) {
            log.info("用户不靠谱认证风控不通过");
            throw new BusinessException(ExceptionMsgEnum.BUSINESS_ERROR.getCode(), Consts.RISK_CONTROL_FAIL_TPS);
        }

    }
}
